package com.ruoyi.web.controller.store.in;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.*;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.RestaurantStoreResourceMapper;
import com.ruoyi.system.mapper.StoreOutDetailMapper;
import com.ruoyi.system.mapper.StoreOutMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.*;
import com.ruoyi.system.service.resp.StoreInDTO;
import io.swagger.annotations.Api;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: ruohao
 * @Date: 2023/10/14
 **/
@RestController
@RequestMapping("/store/in")
@Api(tags = "入库单相关接口")
public class StoreInController extends BaseController {
    @Resource
    private StoreInService storeInService;

    @Resource
    IFoodStockService foodStockService;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private StoreInDetailService storeInDetailService;

    @Resource
    private StorePlanService storePlanService;

    @Resource
    private StorePlanDetailService storePlanDetailService;

    @Resource
    private StoreExamineService storeExamineService;

    @Resource
    private StoreExamineDetailService storeExamineDetailService;

    @Resource
    private ApproveService approveService;

    @Resource
    private VendorService vendorService;

    @Resource
    private StoreOutMapper storeOutMapper;

    @Resource
    private StoreOutDetailMapper storeOutDetailMapper;

    @Resource
    private RestaurantStoreResourceService resourceService;

    @Log(title = "查询入库单", businessType = BusinessType.OTHER)
    @GetMapping("/list")
    public TableDataInfo list(StoreIn storeIn) {
        startPage();
        List<StoreIn> list = storeInService.selectList(storeIn);
        return getDataTable(fillToDTOs(list));
    }

    @Log(title = "查询入库单", businessType = BusinessType.OTHER)
    @GetMapping("/tenList")
    public TableDataInfo tenList() {
        List<StoreIn> list = storeInService.selectTenList();
        return getDataTable(fillToDTOs(list));
    }

    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable Long id) {
        StoreIn storeIn = storeInService.selectById(id);
        StoreInDetail storeInDetail = new StoreInDetail();
        storeInDetail.setInId(id);
        List<StoreInDetail> storeOutDetails = storeInDetailService.selectList(storeInDetail);
        storeIn.setDetailList(storeOutDetails);
        return AjaxResult.success(storeIn);
    }

    @Log(title = "增加入库单", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult add(@Validated @RequestBody StoreIn storeIn) {
//        if (!"正常入库单".equals(storeIn.getType())) {

        if (StringUtils.isNotBlank(storeIn.getPlanId()) && !"无".equals(storeIn.getPlanId())) {
            //园区为全部的不让新增
            if (StringUtils.isNotBlank(SecurityUtils.getUserLocation()) && SecurityUtils.getUserLocation().equals("全部")) {
                throw new BaseException("错误,该登录人园区为全部,不允许新增");
            }

            // 没有采购计划则返回错误
            List<StorePlan> storePlans = storePlanService.selectList(StorePlan.builder()
                    .planId(storeIn.getPlanId()).build());
            if (CollectionUtils.isEmpty(storePlans)) {
                return error("没有 " + storeIn.getPlanId() + " 这个请购单");
            }
            StorePlan storePlan = storePlans.get(0);
            // 采购计划没有启用则返回错误
            if (!"启用".equals(storePlan.getStatus())) {
                return error("请购单 " + storeIn.getPlanId() + " 没有启用");
            }
            // 采购计划没有审批通过则返回错误
            String planApproveStatus = getPlanApproveStatus(storePlan);
            if ("正常入库单".equals(storeIn.getType())) {
                planApproveStatus = "通过";
            }
            if (!"通过".equals(planApproveStatus)) {
                return error("请购单 " + storeIn.getPlanId() + " 还没有通过审批");
            }
            // 创建入库单
            storeIn.setCreateBy(SecurityUtils.getLoginUser().getUser().getNickName());
            Boolean result = storeInService.create(storeIn);
            if (!result) {
                return error();
            }

            // 根据采购计划创建入库明细 以及 检测单
            List<StorePlanDetail> storePlanDetails = storePlanDetailService.selectList(StorePlanDetail.builder()
                    .planId(storePlan.getId()).build());
            createInDetails(storeIn.getId(), storeIn.getType(), storePlanDetails);
            createExamine(storeIn.getId(), storePlanDetails);
        } else {
            // 创建入库单
            storeIn.setCreateBy(SecurityUtils.getLoginUser().getUser().getNickName());
            Boolean result = storeInService.create(storeIn);
            if (!result) {
                return error();
            }
        }
        return success();
    }

    private void createInDetails(Long inId, String inType, List<StorePlanDetail> storePlanDetails) {
        if (CollectionUtils.isEmpty(storePlanDetails)) {
            return;
        }
        String direct = "是";
//        String direct = "否";
//        if (inType != null && inType.contains("自助")) {
//            direct = "是";
//        }
        for (StorePlanDetail storePlanDetail : storePlanDetails) {
            StoreInDetail storeInDetail = new StoreInDetail();
            storeInDetail.setCreateBy(SecurityUtils.getLoginUser().getUser().getNickName());
            storeInDetail.setInId(inId);
            storeInDetail.setPlanDetailId(storePlanDetail.getId());
            storeInDetail.setResourceId(storePlanDetail.getResourceId());
            storeInDetail.setUnit(storePlanDetail.getUnit());
            storeInDetail.setAmount(storePlanDetail.getAmount());
            storeInDetail.setStatus("否");
            storeInDetail.setDirect(direct);
            storeInDetail.setPrice(restaurantStoreResourceMapper.getPrice(storeInDetail.getResourceId()));
            storeInDetailService.create(storeInDetail);
        }
    }

    private String getPlanApproveStatus(StorePlan storePlan) {
        ApproveMission approveMission = approveService.getByActivityd(storePlan.getId(), "采购计划详情审批");
        if (approveMission == null) {
            return null;
        }
        return approveMission.getStatus();
    }

    private void createExamine(Long inId, List<StorePlanDetail> storePlanDetails) {
        StoreExamine storeExamine = new StoreExamine();
        storeExamine.setStoreInId(inId);
        storeExamine.setStatus("检测中");
        storeExamine.setCreateBy(SecurityUtils.getLoginUser().getUser().getNickName());
        storeExamineService.create(storeExamine);

        if (CollectionUtils.isEmpty(storePlanDetails)) {
            return;
        }

        for (StorePlanDetail storePlanDetail : storePlanDetails) {
            StoreExamineDetail storeExamineDetail = new StoreExamineDetail();
            storeExamineDetail.setExamineId(storeExamine.getId());
            storeExamineDetail.setStatus("检测中");
            storeExamineDetail.setResourceId(storePlanDetail.getResourceId());
            storeExamineDetail.setContent("农药残留、新鲜程度等");
            storeExamineDetail.setCreateBy(SecurityUtils.getLoginUser().getUser().getNickName());
            storeExamineDetailService.create(storeExamineDetail);
        }
    }

    @Log(title = "修改入库单", businessType = BusinessType.UPDATE)
    @PutMapping
//    @Transactional(rollbackFor = Exception.class)
    public AjaxResult edit(@Validated @RequestBody StoreIn storeIn) {
        StoreIn old = storeInService.selectById(storeIn.getId());
        if (old == null) {
            return error("未知错误 联系管理员");
        }
        if ("待入库".equals(old.getStatus()) && "已入库".equals(storeIn.getStatus())) {
//            if (StringUtils.isBlank(storeIn.getConfirmer()) || storeIn.getConfirmTime() == null) {
//                return error("修改为已入库状态时，需要有确认人和确认时间");
//            }
            storeIn.setConfirmer(SecurityUtils.getNickName());
            storeIn.setConfirmTime(new Date());//注释
            checkDetails(storeIn.getId());
            //自动完成入库检测单
            completeStoreStoreExamine(old);
        } else if ("已入库".equals(old.getStatus()) && "待入库".equals(storeIn.getStatus())) {
            return error("已入库的入库单已关联到出库单，不可改回待入库状态");
        }
        storeIn.setUpdateBy(SecurityUtils.getLoginUser().getUser().getNickName());
        Boolean result = storeInService.update(storeIn);
        if (!result) {
            return error();
        }
        if ("待入库".equals(old.getStatus()) && "已入库".equals(storeIn.getStatus())) {
            processStoreOut(storeIn.getId(), old.getArea(), storeIn);//生成出库单
            completeStoreStoreExamine(old);
            //入库成功 修改库存
            List<StoreInDetail> details = storeInDetailService.selectList(StoreInDetail.builder().inId(storeIn.getId()).build());
            foodStockService.updateStockByIn(storeIn, details);
            for (StoreInDetail detail : details) {
                RestaurantStoreResource resource = restaurantStoreResourceMapper.selectRestaurantStoreResourceById(detail.getResourceId());
                if (resource != null) {
                    resource.setAvgPrice(detail.getPrice());
                    restaurantStoreResourceMapper.updateRestaurantStoreResource(resource);
                }
            }
        }
        return AjaxResult.success();
    }

    public void completeStoreStoreExamine(StoreIn storeIn) {
        if (storeIn != null && storeIn.getId() != null) {
            StoreExamine query = new StoreExamine();
            query.setStoreInId(storeIn.getId());
            List<StoreExamine> storeExamines = storeExamineService.selectList(query);
            for (StoreExamine storeExamine : storeExamines) {
                storeExamine.setStatus("检测通过");
                storeExamine.setInspector(SecurityUtils.getNickName());
                storeExamine.setCheckTime(storeIn.getInTime() == null ? new Date() : storeIn.getInTime());
                storeExamineService.update(storeExamine);

                StoreExamineDetail storeExamineDetail = new StoreExamineDetail();
                storeExamineDetail.setExamineId(storeExamine.getId());
                List<StoreExamineDetail> detailList = storeExamineDetailService.selectList(storeExamineDetail);
                for (StoreExamineDetail examineDetail : detailList) {
                    examineDetail.setStatus("检测通过");
                    storeExamineDetailService.update(examineDetail);
                }
            }
        }
    }

    private void checkDetails(Long inId) {
        if (inId == null) {
            return;
        }
        List<StoreInDetail> storeInDetails = storeInDetailService.selectList(StoreInDetail.builder().inId(inId).build());
        if (CollectionUtils.isEmpty(storeInDetails)) {
            return;
        }
        for (StoreInDetail detail : storeInDetails) {
            if (StringUtils.isBlank(detail.getUnit())) {
                throw new ServiceException("入库单明细单位不能为空");
            }
            if (detail.getAmount() == null) {
                throw new ServiceException("入库单明细数量不能为空");
            }
            if (detail.getAmount().compareTo(BigDecimal.ZERO) == 0) {
                throw new ServiceException("入库单明细数量不能为0");
            }
//            if (detail.getPrice() == null) {
//                throw new ServiceException("入库单明细单价不能为空");
//            }
//            if (detail.getPrice().compareTo(BigDecimal.ZERO) == 0) {
//                throw new ServiceException("入库单明细单价不能为0");
//            }
            if (detail.getResourceId() == null) {
                throw new ServiceException("入库单明细食材不能为空");
            }
            RestaurantStoreResource resource = resourceService.selectRestaurantStoreResourceById(detail.getResourceId());
            if (resource == null) {
                throw new ServiceException("入库单明细食材id非法");
            }

//            if (!resource.getUnit().equals(detail.getUnit())) {
//                throw new ServiceException("入库单明细单位应该和库存单位一致");
//            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void processStoreOut(Long inId, String area, StoreIn storeIn) {
        try {
            if (inId == null) {
                return;
            }
            if (StringUtils.isBlank(area)) {
                SysUser user = SecurityUtils.getLoginUser().getUser();
                area = user.getLocation();
//                throw new BaseException("错误，园区为空");
            }

            List<StoreInDetail> storeInDetails = storeInDetailService.selectList(StoreInDetail.builder().inId(inId).build());
            if (CollectionUtils.isEmpty(storeInDetails)) {
                return;
            }
//            processResource(storeInDetails);//修改库存在外面修改
            List<StoreOutDetail> storeOutDetails = getFromInDetails(storeInDetails);
            if (CollectionUtils.isEmpty(storeOutDetails)) {
                return;
            }
            StoreOut storeOut = new StoreOut();
            storeOut.setStoreInId(inId);
            storeOut.setOutTime(storeIn == null || storeIn.getInTime() == null ? new Date() : storeIn.getInTime());
            storeOut.setType("直接出库");
            storeOut.setStatus("已出库");

            storeOut.setArea(area);
            storeOut.setCreateBy(SecurityUtils.getNickName());
            storeOut.setCreateTime(new Date());
            storeOut.setConfirmer(SecurityUtils.getNickName());
            storeOut.setConfirmTime(new Date());
            storeOut.setAmount(storeIn.getAmount());

            if (StringUtils.isBlank(storeOut.getArea())) {
                throw new BaseException("错误，登录人园区为空");
            }
            storeOut.setApplicant(sysUserMapper.getNickNameByPost());
            int result = storeOutMapper.insert(storeOut);
            if (result != 1) {
                throw new ServiceException("创建出库单出错");
            }
            storeOutDetails.forEach(s -> {
                s.setOutId(storeOut.getId());
                int detailResult = storeOutDetailMapper.insert(s);
                if (detailResult != 1) {
                    throw new ServiceException("创建出库单明细出错");
                }
            });

            //修改库存
            foodStockService.updateStockByOut(storeOut, storeOutDetails);
        } catch (Exception e) {
            logger.error("入库单直接出库出错", e);
        }
    }

    @Resource
    private RestaurantStoreResourceMapper restaurantStoreResourceMapper;

    private void processResource(List<StoreInDetail> storeInDetails) {
        if (CollectionUtils.isEmpty(storeInDetails)) {
            return;
        }
        storeInDetails = storeInDetails.stream().filter(s -> !"是".equals(s.getDirect()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(storeInDetails)) {
            return;
        }
        for (StoreInDetail detail : storeInDetails) {
            RestaurantStoreResource resource = resourceService.selectRestaurantStoreResourceById(detail.getResourceId());
            RestaurantStoreResource resourceUpdate = new RestaurantStoreResource();
            resourceUpdate.setId(resource.getId());
            resourceUpdate.setAmount(resource.getAmount() + detail.getAmount().intValue());
            restaurantStoreResourceMapper.updateRestaurantStoreResource(resourceUpdate);
        }
    }

    private List<StoreOutDetail> getFromInDetails(List<StoreInDetail> storeInDetails) {
        if (CollectionUtils.isEmpty(storeInDetails)) {
            return new ArrayList<>();
        }
        List<StoreOutDetail> storeOutDetails = new ArrayList<>();
        for (StoreInDetail detail : storeInDetails) {
            if (!"是".equals(detail.getDirect())) {
                continue;
            }
            if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) == 0) {
                continue;
            }
            StoreOutDetail storeOutDetail = new StoreOutDetail();
            storeOutDetail.setResourceId(detail.getResourceId());
            storeOutDetail.setUnit(detail.getUnit());
            storeOutDetail.setAmount(detail.getAmount());
            storeOutDetail.setCreateBy(SecurityUtils.getNickName());
            storeOutDetail.setPrice(detail.getPrice());
            storeOutDetails.add(storeOutDetail);
        }
        return storeOutDetails;
    }

    @Log(title = "获取入库单详情", businessType = BusinessType.DELETE)
    @DeleteMapping("/{id}")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult remove(@PathVariable Long id) {
        StoreExamine query = new StoreExamine();
        query.setStoreInId(id);
        List<StoreExamine> storeExamines = storeExamineService.selectList(query);
        for (StoreExamine storeExamine : storeExamines) {
            storeExamineService.deleteById(storeExamine.getId());

            StoreExamineDetail storeExamineDetail = new StoreExamineDetail();
            storeExamineDetail.setExamineId(storeExamine.getId());
            List<StoreExamineDetail> detailList = storeExamineDetailService.selectList(storeExamineDetail);
            for (StoreExamineDetail examineDetail : detailList) {
                storeExamineDetailService.deleteById(examineDetail.getId());
            }
        }
        return toAjax(storeInService.deleteById(id));
    }

    private List<StoreInDTO> fillToDTOs(List<StoreIn> storeIns) {
        PageInfo oldPage = new PageInfo(storeIns);
        Page<StoreInDTO> newPage = new Page<>();
        newPage.setTotal(oldPage.getTotal());
        if (CollectionUtils.isEmpty(storeIns)) {
            newPage.addAll(Collections.emptyList());
            return newPage;
        }
        List<Long> vendorIds = storeIns.stream().map(StoreIn::getVendorId).collect(Collectors.toList());
        List<Vendor> vendors = vendorService.selectByIds(vendorIds);
        Map<Long, Vendor> vendorMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(vendors)) {
            vendorMap = vendors.stream().collect(Collectors.toMap(Vendor::getId, v -> v));
        }

        for (StoreIn storeIn : storeIns) {
            StoreInDTO storeInDTO = new StoreInDTO();
            storeInDTO.setId(storeIn.getId());
            storeInDTO.setVendorId(storeIn.getVendorId());
            storeInDTO.setVendorName(Optional.ofNullable(vendorMap.get(storeIn.getVendorId())).map(Vendor::getName).orElse(null));
//            storeInDTO.setInTime(storeIn.getInTime());
            storeInDTO.setConfirmer(storeIn.getConfirmer());
            storeInDTO.setConfirmTime(storeIn.getConfirmTime());
            storeInDTO.setStatus(storeIn.getStatus());
            storeInDTO.setType(storeIn.getType());
            storeInDTO.setAmount(getTotalPrice(storeIn.getId()));
            storeInDTO.setPlanId(storeIn.getPlanId());
            storeInDTO.setCreateBy(storeIn.getCreateBy());
            storeInDTO.setCreateTime(storeIn.getCreateTime());
            storeInDTO.setUpdateBy(storeIn.getUpdateBy());
            storeInDTO.setUpdateTime(storeIn.getUpdateTime());
            storeInDTO.setRemark(storeIn.getRemark());
            storeInDTO.setImageUrl(storeIn.getImageUrl());
            storeInDTO.setInTime(storeIn.getInTime());
            storeInDTO.setArea(storeIn.getArea());
            List<StoreExamine> storeExamines = storeExamineService.selectList(StoreExamine.builder()
                    .storeInId(storeIn.getId()).build());
            if (!CollectionUtils.isEmpty(storeExamines)) {
                storeInDTO.setExamineStatus(storeExamines.get(0).getStatus());
                storeInDTO.setExamineId(storeExamines.get(0).getId());
            }
            newPage.add(storeInDTO);
        }
        return newPage;
    }

    private BigDecimal getTotalPrice(Long inId) {
        List<StoreInDetail> storeInDetails = storeInDetailService.selectList(StoreInDetail.builder().inId(inId).build());
        if (CollectionUtils.isEmpty(storeInDetails)) {
            return BigDecimal.ZERO;
        }
        BigDecimal total = BigDecimal.ZERO;
        for (StoreInDetail storeInDetail : storeInDetails) {
            BigDecimal unitPrice = Optional.ofNullable(storeInDetail.getPrice()).orElse(BigDecimal.ZERO);
            BigDecimal amount = Optional.ofNullable(storeInDetail.getAmount()).orElse(BigDecimal.ZERO);
            total = total.add(unitPrice.multiply(amount));
        }
        return total;
    }
}
